package com.example.framework509.codeGen.utils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.framework509.codeGen.entity.middlePojp.EntityContainer;
import com.example.framework509.common.exceptions.NotExistException;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Component
public class CodeGenUtils {

    public static List<String> getTemplates() {
        List<String> templates = new ArrayList<String>();
        templates.add("template/Entity.java.vm");
        templates.add("template/Mapper.java.vm");
        templates.add("template/ServiceImpl.java.vm");
        templates.add("template/Controller.java.vm");
        return templates;
    }

    public void build(EntityContainer container, String mainPath, ZipOutputStream zip) {

        //设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(prop);
        mainPath = StringUtils.isBlank(mainPath) ? "io.hu" : mainPath;
        //封装模板数据
        Map<String, Object> map = new HashMap<>();
        //map.put("tableName", tableEntity.getTableName());
        map.put("mainPath", mainPath);
        map.put("moduleName", container.getModelName());
        map.put("entityName", container.getEntityName());
        map.put("entityNameUpper", StringUtil.firstUpperCase(container.getEntityName()));
        map.put("entityType", container.getMapperType() == null ? "entity" : "mapper");
        if (container.getPrimaryEntity() != null) {
            map.put("mapperType", container.getMapperType());
            map.put("primaryModule", container.getPrimaryModule());
            map.put("primaryEntity", StringUtil.firstUpperCase(container.getPrimaryEntity()));
            map.put("primaryEntityLower", StringUtil.firstLowerCase(container.getPrimaryEntity()));
            map.put("secondaryModule", container.getSecondaryModule());
            map.put("secondaryEntity", StringUtil.firstUpperCase(container.getSecondaryEntity()));
            map.put("secondaryEntityLower", StringUtil.firstLowerCase(container.getSecondaryEntity()));
        }
        map.put("fieldsInfo", container.getProps());
        map.put("entityMenu", -1);

        VelocityContext context = new VelocityContext(map);

        List<String> templates = getTemplates();
        for (String template : templates) {
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, "UTF-8");
            tpl.merge(context, sw);

            try {
                //添加到zip
                zip.putNextEntry(new ZipEntry(getFileName(template, StringUtil.firstUpperCase(container.getEntityName()), mainPath, container.getModelName())));
                IOUtils.write(sw.toString(), zip, "UTF-8");
                IOUtils.closeQuietly(sw);
                zip.closeEntry();
            } catch (IOException e) {
                throw new NotExistException("渲染模板失败：" + container.getEntityName() + "/detail info:" + e.toString());
            }
        }
    }

    public void addStaticFile(String mainPath, String fileRootPath, ZipOutputStream zip) {
        List<String> filePath = getFilePath(fileRootPath);
        try {
            for (String path : filePath) {
                File fileV = new File(path);
                File file = new File(fileV.getAbsolutePath());
                byte[] buf = new byte[1024 * 2];
                zip.putNextEntry(new ZipEntry(getFileName(mainPath, path)));
                int len;
                FileInputStream in = new FileInputStream(file);

                while ((len = in.read(buf)) != -1) {
                    zip.write(buf, 0, len);
                }

                zip.closeEntry();
                in.close();
            }
        } catch (Exception e) {
            throw new RuntimeException("渲染模板失败", e);
        }
    }

    private List<String> getFilePath(String fileRootPath) {
        List<String> paths = new ArrayList<>();
        File root = new File(fileRootPath);
        File fileList[] = root.listFiles();
        for (int i = 0; i < fileList.length; i++) {
            File fs = fileList[i];
            if (fs.isDirectory()) {
                List<String> filePaths = getFilePath(fs.getPath());
                paths.addAll(filePaths);
            } else paths.add(fs.getPath());
        }
        return paths;
    }

    public static String getFileName(String mainPath, String filePath) {
        String packagePath = "main" + File.separator + "java" + File.separator;
        if (StringUtils.isNotBlank(mainPath)) {
            packagePath += mainPath.replace(".", File.separator) + File.separator;
        }
        packagePath += filePath.replace("src\\main\\resources\\static\\", "").replace("\\", File.separator);
        return packagePath;
    }

    public static String getFileName(String template, String className, String mainPath, String moduleName) {
        String packagePath = "main" + File.separator + "java" + File.separator;
        if (StringUtils.isNotBlank(mainPath)) {
            packagePath += mainPath.replace(".", File.separator) + File.separator + moduleName + File.separator;
        }
        if (template.contains("Entity.java.vm")) {
            return packagePath + "entity" + File.separator + className + ".java";
        }

        if (template.contains("Mapper.java.vm")) {
            return packagePath + "mapper" + File.separator + className + "Mapper.java";
        }

        if (template.contains("ServiceImpl.java.vm")) {
            return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
        }

        if (template.contains("Controller.java.vm")) {
            return packagePath + "controller" + File.separator + className + "Controller.java";
        }

        return null;
    }

}
